/**
 * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md.
 */

/* global CKEDITOR */

import { getEditorNamespace } from './utils/geteditornamespace.js';

const DEFAULT_CONFIG = {
  toolbarGroups: [
    { name: 'document', groups: ['mode', 'document', 'doctools'] },
    { name: 'clipboard', groups: ['clipboard', 'undo'] },
    { name: 'editing', groups: ['find', 'selection', 'editing'] },
    { name: 'forms', groups: ['forms'] },
    { name: 'basicstyles', groups: ['basicstyles', 'cleanup'] },
    { name: 'paragraph', groups: ['list', 'align', 'bidi', 'paragraph'] },
    { name: 'insert', groups: ['insert'] }
  ],

  //上传图片窗口用到的接口
  filebrowserImageUploadUrl: '/api/common/ueditor/getUploadPasterImageUrl',
  filebrowserUploadUrl: '/api/common/ueditor/getUploadPasterImageUrl',

  // 使上传图片弹窗出现对应的“上传”tab标签
  removeDialogTabs: 'image:advanced;link:advanced',

  //粘贴图片时用得到
  extraPlugins: 'uploadimage',
  uploadUrl: '/api/common/ueditor/getUploadPasterImageUrl'
};

export default {
  name: 'ckeditor',

  render(createElement) {
    let config = {};
    let children = [];
    if (this.config.readOnly) {
      config['domProps'] = {
        innerHTML: this.value
      };
    } else {
      children.push(createElement(this.tagName));
    }
    return createElement('div', config, children);
  },

  props: {
    value: {
      type: String,
      default: ''
    },
    type: {
      type: String,
      default: 'classic',
      validator: (type) => ['classic', 'inline'].includes(type)
    },
    editorUrl: {
      type: String,
      default: 'https://cdn.ckeditor.com/4.13.0/standard/ckeditor.js'
    },
    config: {
      type: Object,
      default: () => {}
    },
    tagName: {
      type: String,
      default: 'textarea'
    },
    readOnly: {
      type: Boolean,
      default: null // Use the null for default value, so `config.readOnly` can take precedence.
    }
  },

  mounted() {
    if (!this.config.readOnly) {
      getEditorNamespace(this.editorUrl).then(() => {
        if (this.$_destroyed) {
          return;
        }

        const config = {
          ...DEFAULT_CONFIG,
          ...this.config
        };

        if (this.readOnly !== null) {
          config.readOnly = this.readOnly;
        }

        CKEDITOR.disableAutoInline = true;
        const method = this.type === 'inline' ? 'inline' : 'replace';
        const element = this.$el || this.$el.firstElementChild;
        const editor = (this.instance = CKEDITOR[method](element, config));

        editor.on('instanceReady', () => {
          const undo = editor.undoManager;
          const data = this.value;

          if (undo) {
            undo.lock();
          }

          editor.setData(data, {
            callback: () => {
              this.$_setUpEditorEvents();

              const newData = editor.getData();

              // Locking undoManager prevents 'change' event.
              // Trigger it manually to update bound data.
              if (data !== newData) {
                this.$once('input', () => {
                  this.$emit('ready', editor);
                });

                this.$emit('input', newData);
              } else {
                this.$emit('ready', editor);
              }

              if (undo) {
                undo.unlock();
              }
            }
          });
        });
      });
    }
  },

  beforeDestroy() {
    if (this.instance) {
      this.instance.destroy();
    }

    this.$_destroyed = true;
  },

  watch: {
    value(val) {
      if (this.instance) {
        if (this.instance.getData() !== val) {
          this.instance.setData(val);
        }
      }
    },

    readOnly(val) {
      this.instance.setReadOnly(val);
    }
  },

  methods: {
    $_setUpEditorEvents() {
      const editor = this.instance;

      editor.on('change', (evt) => {
        const data = editor.getData();

        // Editor#change event might be fired without actual data change.
        if (this.value !== data) {
          // The compatibility with the v-model and general Vue.js concept of input–like components.
          this.$emit('input', data, evt, editor);
        }
      });

      editor.on('focus', (evt) => {
        var val = new RegExp('<p>请输入内容</p>');
        if (this.value != '') {
          this.value = this.value.replace(val, '');
        }
        this.$emit('focus', evt, editor);
      });

      editor.on('blur', (evt) => {
        const data = editor.getData();
        if (this.value !== data) {
          // The compatibility with the v-model and general Vue.js concept of input–like components.
          this.$emit('input', data, evt, editor);
        }
        if (!this.value) {
          this.value = '<p>请输入内容</p>';
        }
        this.$emit('blur', evt, editor);
      });
    }
  }
};
